package ucuserslogic

import (
	"context"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	"math/rand"
	"navi-mumbai/app/rpc/model/pg/usercenter"
	pb2 "navi-mumbai/app/rpc/wallet/pb"
	"navi-mumbai/common/auth"
	"navi-mumbai/common/key/appsflyerkey"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/idkey"
	"navi-mumbai/common/key/userkey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"
	"navi-mumbai/third/appsflyer"
	"navi-mumbai/third/login/fb"
	"navi-mumbai/third/login/google"
	"strconv"
	"time"

	"navi-mumbai/app/rpc/usercenter/internal/svc"
	"navi-mumbai/app/rpc/usercenter/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type RegisterLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
	lRand *rand.Rand
}

func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
	return &RegisterLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
		lRand:  rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (l *RegisterLogic) Register(in *pb.LoginUserReq) (*pb.LoginUserResp, error) {
	defer utils.RecoverPanic()

	l.Logger.Infof("Register. authkey: %s, authType: %s", in.AuthKey, in.AuthType)
	// 查询是否已经注册
	uac, err := l.svcCtx.UserAccountModel.FindOneByAuthKeyAuthType(l.ctx, in.AuthKey, in.AuthType)
	if err != nil && err != usercenter.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}
	if uac != nil {
		l.Logger.Errorf("user already exist")
		return nil, xerr.NewGrpcErrCodeMsg(xerr.UserAlreadyExist, "user already exist")
	}
	return l.doRegister(in)
}

// 注册
func (l *RegisterLogic) doRegister(in *pb.LoginUserReq) (*pb.LoginUserResp, error) {
	var err error
	var uid int64
	l.Logger.Infof("in doRegister...")
	// uid
	uid, err = l.svcCtx.UserAccountModel.FindLMaxUid(l.ctx)
	if err != nil && err != sqlx.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, fmt.Sprintf("err:%+v", err))
	}
	if uid < idkey.UidStart {
		uid += idkey.UidStart
	} else {
		uid += 1
	}

	if in.UserChannel == "" {
		in.UserChannel = userkey.UserChannelDefault
	}

	// user account
	uac := new(usercenter.UserAccount)
	uac.Uid = uid
	uac.AuthKey = in.AuthKey
	uac.AuthType = in.AuthType
	uac.UserChannel = userkey.GetUserChannelNo(in.UserChannel)
	if len(in.UserPass) > 0 && in.AuthType == userkey.UserAuthTypePasswd {
		var tmpb []byte
		tmpb, err = auth.GenerateFromPassword(in.UserPass)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.ServerCommonError, fmt.Sprintf("err:%+v", err))
		}
		uac.Userpass = string(tmpb[:])
	}
	uac.UserType = userkey.UserTypeNormalUser
	uac.AccountState = userkey.AccountStateNormal
	uac.RegIp = in.Ip
	uac.RegDevice = in.Device
	uac.RegDeviceId = in.DeviceId
	uac.AppsFlyerUid = in.AppsFlyerUID

	// user noAuthLogin stat
	uls := new(usercenter.UserLoginStat)
	uls.Uid = uac.Uid
	uls.LoginTime = time.Now()
	uls.TodayLoginCnt = 1
	uls.LoginCntSum = 1
	uls.AppVer = strconv.FormatInt(in.AppVer, 10)
	uls.LoginIp = in.Ip
	uls.LoginDevice = in.Device
	uls.LoginDeviceId = in.DeviceId
	uls.LoginDays = 1

	// user profile
	up := new(usercenter.UserProfile)
	up.Uid = uac.Uid
	up.Email = in.Email
	idx := uid % (int64(len(userkey.DefaultAvatar)))
	up.Avatar = userkey.DefaultAvatar[idx]
	up.Language = userkey.LanguageEnIN
	up.Name = in.AuthKey

	// user notify msg stat
	unms := new(usercenter.UserNotifyMsgStat)
	unms.Uid = uac.Uid

	// user reward stat
	ugs := new(usercenter.UserRewardStat)
	ugs.Uid = uac.Uid
	ugs.NotReceived = 1 // 注册赠送金币
	ugs.Total = 1

	//
	unm := new(usercenter.UserReward)
	*unm = usercenter.UserReward{
		Uid:          uac.Uid,
		RewardType:   walletkey.UsingCurrencyType, // userkey.RewardTypeGold,
		RewardAmount: userkey.RegisterRewardMoneyAmount,
		ActivityId:   userkey.ActivityIdRegister,
		State:        userkey.RewardStateCreated,
	}

	//
	curTime := time.Now()
	url := new(usercenter.UserRewardLimit)
	*url = usercenter.UserRewardLimit{
		Uid:                   uac.Uid,
		TodayLuckyRewardCnt:   0,
		LuckyRewardUpdateTime: curTime,
		TodayLoginRewardCnt:   0,
		LoginRewardUpdateTime: curTime,
	}
	l.Logger.Infof("in doRegister")

	err = l._trans(uac, uls, up, unms, ugs, unm, url)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	// 生成token
	generateTokenLogic := NewGenerateTokenLogic(l.ctx, l.svcCtx)
	tokenResp, err := generateTokenLogic.GenerateToken(&pb.GenerateTokenReq{
		Uid:         uac.Uid,
		UserChannel: uac.UserChannel,
		AppVer:      in.AppVer,
		AuthKey:     in.AuthKey,
		AuthType:    in.AuthType,
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.TokenGenerateError, err.Error())
	}

	// app config
	var appConfig *usercenter.AppConfig
	appConfig, err = l.svcCtx.AppConfigModel.FindOne(l.ctx, in.AppVer)
	if err != nil && err != usercenter.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	rsp := pb.LoginUserResp{
		Account:       &pb.UserAccount{Uid: uac.Uid, AccountState: uac.AccountState, Username: in.AuthKey, IsNewUser: dbkey.Enable},
		Profile:       &pb.UserProfile{Email: utils.FormatEmail(in.Email), Avatar: up.Avatar, Language: up.Language},
		Token:         tokenResp,
		NotifyMsgStat: &pb.UserNotifyMsgStat{},
		AppConfig:     &pb.AppConfig{},
		BannerConfig: &pb.BannerConfig{
			List: make([]*pb.BannerData, 0),
		},
		RewardStat: &pb.UserRewardStat{},
	}
	if appConfig != nil {
		rsp.AppConfig.PayState = appConfig.PayState
		rsp.AppConfig.TextState = appConfig.TextState
		rsp.AppConfig.RankState = appConfig.RankState
	}

	// banner config
	var bannerConfig []*usercenter.BannerConfig
	bannerConfig, err = l.svcCtx.BannerConfigModel.Find(l.ctx, userkey.BannerStateOpen, 1, 20)
	if len(bannerConfig) > 0 {
		for i := 0; i < len(bannerConfig); i++ {
			rsp.BannerConfig.List = append(rsp.BannerConfig.List, &pb.BannerData{
				Id:       bannerConfig[i].Id,
				Image:    bannerConfig[i].BannerImage,
				Url:      bannerConfig[i].Url,
				PagePath: bannerConfig[i].PagePath,
				Order:    bannerConfig[i].BannerOrder,
			})
		}
	}
	// 邀请注册，返回佣金, 走异步，不阻塞主流程
	l.afterHandleInvite(uid, in.DeviceId, in.AuthKey, up.Name)
	// 给appsflyer上报事件， 走步调用， 不阻塞主流程
	l.RepoertAppsFlyerByFirstRegister(uac.AppsFlyerUid)
	// login log
	addLoginLog(l.ctx, l.svcCtx, uac.Uid, uac.UserChannel)

	l.Logger.Infof("register success userId %d userName %s Email %s ", rsp.Account.Uid, rsp.Account.Username, rsp.Profile.Email)
	return &rsp, nil
}

func (l *RegisterLogic) _trans(uAccount *usercenter.UserAccount, uLoginStat *usercenter.UserLoginStat, uProfile *usercenter.UserProfile,
	uNotifyMsgStat *usercenter.UserNotifyMsgStat, uRewardStat *usercenter.UserRewardStat, uReward *usercenter.UserReward, uRewardLimit *usercenter.UserRewardLimit) error {
	return l.svcCtx.UserAccountModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		_, err2 := l.svcCtx.UserAccountModel.InsertTrans(ctx, tx, uAccount)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		_, err2 = l.svcCtx.UserLoginStatModel.InsertTrans(ctx, tx, uLoginStat)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		_, err2 = l.svcCtx.UserProfileModel.InsertTrans(ctx, tx, uProfile)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		_, err2 = l.svcCtx.UserNotifyMsgStatModel.InsertTrans(ctx, tx, uNotifyMsgStat)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		_, err2 = l.svcCtx.UserRewardStatModel.InsertTrans(ctx, tx, uRewardStat)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		// 注册送金币
		_, err2 = l.svcCtx.UserRewardModel.InsertTrans(ctx, tx, uReward)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		_, err2 = l.svcCtx.UserRewardLimitModel.InsertTrans(ctx, tx, uRewardLimit)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
}

// 登陆日志
func addLoginLog(ctx context.Context, svcCtx *svc.ServiceContext, uid int64, channel int64) {
	// 次日登陆上报
	processingNextDayLoginReport(ctx, svcCtx, uid)

	//var err error
	//kqmsg2 := kqmsg.KqAddUserLoginLogMsg{
	//	Uid:         uid,
	//	UserChannel: channel,
	//	LoginTime:   time.Now().Format(dbkey.DateTimeCNFormat),
	//}
	//var kBuf2 []byte
	//kBuf2, err = json.Marshal(&kqmsg2)
	//if err != nil {
	//	logx.WithContext(ctx).Errorf("addLoginLog kqmsg2 json.Marshal err:%+v", err)
	//	return
	//}
	//err = svcCtx.KqAddUserLoginLogClient.Push(string(kBuf2[:]))
	//if err != nil {
	//	logx.WithContext(ctx).Errorf("addLoginLog Kq Push err:%+v", err)
	//	return
	//}
}

func processingNextDayLoginReport(ctx context.Context, svcCtx *svc.ServiceContext, uid int64) {
	logx.WithContext(ctx).Infof("processingNextDayLoginReport start")
	userAccount, err := svcCtx.UserAccountModel.FindOne(ctx, uid)
	if err != nil {
		logx.WithContext(ctx).Errorf("err == ", zap.Error(err))
		return
	}
	// 时间处理， 只有注册之后， 第二天登录才上报
	createTime := userAccount.CreateTime
	towTimeStamp := createTime.AddDate(0, 0, 1).Unix()
	towTime := time.Unix(towTimeStamp, 0)
	gap := time.Now().Unix() - towTime.Unix()
	logx.WithContext(ctx).Infof("processingNextDayLoginReport gap: %d", gap)
	// 小于表示， 还没到明天， 大于 86400 表示已经超过第二天了
	if gap < 0 || gap > 86400 {
		return
	}

	go appsflyer.ReportAppsFlyerEvent(ctx, appsflyerkey.LandingTheNextDay, userAccount.AppsFlyerUid, "")
	logx.WithContext(ctx).Infof("processingNextDayLoginReport end")
}

// 注册
func (l *RegisterLogic) doVerifyCodeUserLoginRegister(in *pb.VerifyCodeUserLoginReq) (*pb.LoginUserResp, error) {
	defer utils.RecoverPanic()

	var err error
	var uid int64

	// uid
	uid, err = l.svcCtx.UserAccountModel.FindLMaxUid(l.ctx)
	if err != nil && err != sqlx.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, fmt.Sprintf("err:%+v", err))
	}
	if uid < idkey.UidStart {
		uid += idkey.UidStart
	} else {
		uid += 1
	}
	if in.UserChannel == "" {
		in.UserChannel = userkey.UserChannelDefault
	}

	// user account
	uac := new(usercenter.UserAccount)
	uac.Uid = uid
	uac.AuthKey = strconv.FormatInt(in.AreaNo, 10) + strconv.FormatInt(in.PhoneNo, 10)
	uac.AuthType = userkey.UserAuthTypeVerifyCode
	uac.UserChannel = userkey.GetUserChannelNo(in.UserChannel)
	uac.UserType = userkey.UserTypeNormalUser
	uac.AccountState = userkey.AccountStateNormal
	uac.RegDevice = in.Device
	uac.RegDeviceId = in.DeviceId
	uac.RegIp = in.Ip

	// user noAuthLogin stat
	uls := new(usercenter.UserLoginStat)
	uls.Uid = uac.Uid
	uls.LoginTime = time.Now()
	uls.TodayLoginCnt = 1
	uls.LoginCntSum = 1
	uls.AppVer = strconv.FormatInt(in.AppVer, 10)
	uls.LoginDevice = in.Device
	uls.LoginDeviceId = in.DeviceId
	uls.LoginDays = 1

	// user profile
	up := new(usercenter.UserProfile)
	up.Uid = uac.Uid
	idx := uid % (int64(len(userkey.DefaultAvatar)))
	up.Avatar = userkey.DefaultAvatar[idx]
	up.Language = userkey.LanguageEnIN
	up.AreaNo = in.AreaNo
	up.PhoneNo = in.PhoneNo
	up.Name = utils.FormatAccountByPhone(up.PhoneNo)

	// user notify msg stat
	unms := new(usercenter.UserNotifyMsgStat)
	unms.Uid = uac.Uid

	// user reward stat
	ugs := new(usercenter.UserRewardStat)
	ugs.Uid = uac.Uid
	ugs.NotReceived = 1 // 注册赠送金币
	ugs.Total = 1

	//
	unm := new(usercenter.UserReward)
	*unm = usercenter.UserReward{
		Uid:          uac.Uid,
		RewardType:   walletkey.UsingCurrencyType, //userkey.RewardTypeGold,
		RewardAmount: userkey.RegisterRewardMoneyAmount,
		ActivityId:   userkey.ActivityIdRegister,
		State:        userkey.RewardStateCreated,
	}

	//
	curTime := time.Now()
	url := new(usercenter.UserRewardLimit)
	*url = usercenter.UserRewardLimit{
		Uid:                   uac.Uid,
		TodayLuckyRewardCnt:   0,
		LuckyRewardUpdateTime: curTime,
		TodayLoginRewardCnt:   0,
		LoginRewardUpdateTime: curTime,
	}

	err = l._trans(uac, uls, up, unms, ugs, unm, url)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	// 生成token
	generateTokenLogic := NewGenerateTokenLogic(l.ctx, l.svcCtx)
	tokenResp, err := generateTokenLogic.GenerateToken(&pb.GenerateTokenReq{
		Uid:         uac.Uid,
		UserChannel: uac.UserChannel,
		AppVer:      in.AppVer,
		AuthKey:     uac.AuthKey,
		AuthType:    userkey.UserAuthTypeVerifyCode,
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.TokenGenerateError, err.Error())
	}

	// app config
	var appConfig *usercenter.AppConfig
	appConfig, err = l.svcCtx.AppConfigModel.FindOne(l.ctx, in.AppVer)
	if err != nil && err != usercenter.ErrNotFound {
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	rsp := pb.LoginUserResp{
		Account: &pb.UserAccount{Uid: uac.Uid, AccountState: uac.AccountState, Username: up.Name, IsNewUser: dbkey.Disable},
		Profile: &pb.UserProfile{
			Email:    utils.FormatEmail(up.Email),
			Avatar:   up.Avatar,
			Language: up.Language,
			AreaNo:   up.AreaNo,
			PhoneNo:  up.PhoneNo,
		},
		Token:         tokenResp,
		NotifyMsgStat: &pb.UserNotifyMsgStat{},
		AppConfig:     &pb.AppConfig{},
		BannerConfig: &pb.BannerConfig{
			List: make([]*pb.BannerData, 0),
		},
		RewardStat: &pb.UserRewardStat{},
	}
	if appConfig != nil {
		rsp.AppConfig.PayState = appConfig.PayState
		rsp.AppConfig.TextState = appConfig.TextState
		rsp.AppConfig.RankState = appConfig.RankState
	}

	// banner config
	var bannerConfig []*usercenter.BannerConfig
	bannerConfig, err = l.svcCtx.BannerConfigModel.Find(l.ctx, userkey.BannerStateOpen, 1, 20)
	if len(bannerConfig) > 0 {
		for i := 0; i < len(bannerConfig); i++ {
			rsp.BannerConfig.List = append(rsp.BannerConfig.List, &pb.BannerData{
				Id:       bannerConfig[i].Id,
				Image:    bannerConfig[i].BannerImage,
				Url:      bannerConfig[i].Url,
				PagePath: bannerConfig[i].PagePath,
				Order:    bannerConfig[i].BannerOrder,
			})
		}
	}
	// 邀请注册，返回佣金, 走异步，不阻塞主流程
	l.afterHandleInvite(uid, in.DeviceId, uac.AuthKey, up.Name)
	// 给appsflyer上报事件， 走步调用， 不阻塞主流程
	l.RepoertAppsFlyerByFirstRegister(uac.AppsFlyerUid)
	// login log
	addLoginLog(l.ctx, l.svcCtx, uac.Uid, uac.UserChannel)

	// 保存历史记录
	_, err = l.svcCtx.UserVerifyLogModel.Insert(l.ctx, &usercenter.UserVerifyLog{Uid: uac.Uid, VerifyPass: in.VerifyCode})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
	}
	return &rsp, nil
}

// 注册
func (l *RegisterLogic) doFbUserLoginRegister(in *pb.FbUserLoginReq, resp *fb.GetFbUserInfoResp) (*pb.LoginUserResp, error) {
	defer utils.RecoverPanic()

	var err error
	var uid int64

	// uid
	uid, err = l.svcCtx.UserAccountModel.FindLMaxUid(l.ctx)
	if err != nil && err != sqlx.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, fmt.Sprintf("err:%+v", err))
	}
	if uid < idkey.UidStart {
		uid += idkey.UidStart
	} else {
		uid += 1
	}
	if in.UserChannel == "" {
		in.UserChannel = userkey.UserChannelDefault
	}

	// user account
	uac := new(usercenter.UserAccount)
	uac.Uid = uid
	uac.AuthKey = resp.Data.Id
	uac.AuthType = userkey.UserAuthTypeFB
	uac.UserChannel = userkey.GetUserChannelNo(in.UserChannel)
	uac.UserType = userkey.UserTypeNormalUser
	uac.AccountState = userkey.AccountStateNormal
	uac.RegIp = in.Ip
	uac.RegDevice = in.Device
	uac.RegDeviceId = in.DeviceId
	uac.AppsFlyerUid = in.AppsFlyerUID

	// user noAuthLogin stat
	uls := new(usercenter.UserLoginStat)
	uls.Uid = uac.Uid
	uls.LoginTime = time.Now()
	uls.TodayLoginCnt = 1
	uls.LoginCntSum = 1
	uls.AppVer = strconv.FormatInt(in.AppVer, 10)
	uls.LoginIp = in.Ip
	uls.LoginDevice = in.Device
	uls.LoginDeviceId = in.DeviceId
	uls.LoginDays = 1

	// user profile
	up := new(usercenter.UserProfile)
	up.Uid = uac.Uid
	up.Email = resp.Data.Email
	idx := uid % (int64(len(userkey.DefaultAvatar)))
	up.Avatar = userkey.DefaultAvatar[idx]
	up.Language = userkey.LanguageEnIN
	up.Name = utils.FormatAccountByName(resp.Data.Name)

	// user notify msg stat
	unms := new(usercenter.UserNotifyMsgStat)
	unms.Uid = uac.Uid

	// user reward stat
	ugs := new(usercenter.UserRewardStat)
	ugs.Uid = uac.Uid
	ugs.NotReceived = 1 // 注册赠送金币
	ugs.Total = 1

	//
	unm := new(usercenter.UserReward)
	*unm = usercenter.UserReward{
		Uid:          uac.Uid,
		RewardType:   walletkey.UsingCurrencyType, //userkey.RewardTypeGold,
		RewardAmount: userkey.RegisterRewardMoneyAmount,
		ActivityId:   userkey.ActivityIdRegister,
		State:        userkey.RewardStateCreated,
	}

	//
	curTime := time.Now()
	url := new(usercenter.UserRewardLimit)
	*url = usercenter.UserRewardLimit{
		Uid:                   uac.Uid,
		TodayLuckyRewardCnt:   0,
		LuckyRewardUpdateTime: curTime,
		TodayLoginRewardCnt:   0,
		LoginRewardUpdateTime: curTime,
	}

	err = l._trans(uac, uls, up, unms, ugs, unm, url)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	// 生成token
	generateTokenLogic := NewGenerateTokenLogic(l.ctx, l.svcCtx)
	tokenResp, err := generateTokenLogic.GenerateToken(&pb.GenerateTokenReq{
		Uid:         uac.Uid,
		UserChannel: uac.UserChannel,
		AppVer:      in.AppVer,
		AuthKey:     resp.Data.Id,
		AuthType:    userkey.UserAuthTypeFB,
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.TokenGenerateError, err.Error())
	}

	// app config
	var appConfig *usercenter.AppConfig
	appConfig, err = l.svcCtx.AppConfigModel.FindOne(l.ctx, in.AppVer)
	if err != nil && err != usercenter.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	rsp := pb.LoginUserResp{
		Account:       &pb.UserAccount{Uid: uac.Uid, AccountState: uac.AccountState, Username: up.Name, IsNewUser: dbkey.Disable},
		Profile:       &pb.UserProfile{Email: utils.FormatEmail(up.Email), AreaNo: up.AreaNo, PhoneNo: up.PhoneNo, Avatar: up.Avatar, Language: up.Language},
		Token:         tokenResp,
		NotifyMsgStat: &pb.UserNotifyMsgStat{},
		AppConfig:     &pb.AppConfig{},
		BannerConfig: &pb.BannerConfig{
			List: make([]*pb.BannerData, 0),
		},
		RewardStat: &pb.UserRewardStat{},
	}
	if appConfig != nil {
		rsp.AppConfig.PayState = appConfig.PayState
		rsp.AppConfig.TextState = appConfig.TextState
		rsp.AppConfig.RankState = appConfig.RankState
	}

	// banner config
	var bannerConfig []*usercenter.BannerConfig
	bannerConfig, err = l.svcCtx.BannerConfigModel.Find(l.ctx, userkey.BannerStateOpen, 1, 20)
	if len(bannerConfig) > 0 {
		for i := 0; i < len(bannerConfig); i++ {
			rsp.BannerConfig.List = append(rsp.BannerConfig.List, &pb.BannerData{
				Id:       bannerConfig[i].Id,
				Image:    bannerConfig[i].BannerImage,
				Url:      bannerConfig[i].Url,
				PagePath: bannerConfig[i].PagePath,
				Order:    bannerConfig[i].BannerOrder,
			})
		}
	}
	// 邀请注册，返回佣金, 走异步，不阻塞主流程
	l.afterHandleInvite(uid, in.DeviceId, resp.Data.Id, up.Name)
	// 给appsflyer上报事件， 走步调用， 不阻塞主流程
	l.RepoertAppsFlyerByFirstRegister(uac.AppsFlyerUid)
	// login log
	addLoginLog(l.ctx, l.svcCtx, uac.Uid, uac.UserChannel)

	// 保存历史记录
	_, err = l.svcCtx.UserVerifyLogModel.Insert(l.ctx, &usercenter.UserVerifyLog{Uid: uac.Uid, VerifyPass: in.FbToken})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
	}
	return &rsp, nil
}

// 注册
func (l *RegisterLogic) doGoogleUserLoginRegister(in *pb.GoogleUserLoginReq, resp *google.VerifyResultResp) (*pb.LoginUserResp, error) {
	defer utils.RecoverPanic()

	var err error
	var uid int64

	// uid
	uid, err = l.svcCtx.UserAccountModel.FindLMaxUid(l.ctx)
	if err != nil && err != sqlx.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, fmt.Sprintf("err:%+v", err))
	}
	if uid < idkey.UidStart {
		uid += idkey.UidStart
	} else {
		uid += 1
	}
	if in.UserChannel == "" {
		in.UserChannel = userkey.UserChannelDefault
	}

	// user account
	uac := new(usercenter.UserAccount)
	uac.Uid = uid
	uac.AuthKey = resp.Data.Sub
	uac.AuthType = userkey.UserAuthTypeGoogle
	uac.UserChannel = userkey.GetUserChannelNo(in.UserChannel)
	uac.UserType = userkey.UserTypeNormalUser
	uac.AccountState = userkey.AccountStateNormal
	uac.RegIp = in.Ip
	uac.RegDevice = in.Device
	uac.RegDeviceId = in.DeviceId
	uac.AppsFlyerUid = in.AppsFlyerUID

	// user noAuthLogin stat
	uls := new(usercenter.UserLoginStat)
	uls.Uid = uac.Uid
	uls.LoginTime = time.Now()
	uls.TodayLoginCnt = 1
	uls.LoginCntSum = 1
	uls.AppVer = strconv.FormatInt(in.AppVer, 10)
	uls.LoginIp = in.Ip
	uls.LoginDevice = in.Device
	uls.LoginDeviceId = in.DeviceId
	uls.LoginDays = 1

	// user profile
	up := new(usercenter.UserProfile)
	up.Uid = uac.Uid
	up.Email = resp.Data.Email
	idx := uid % (int64(len(userkey.DefaultAvatar)))
	up.Avatar = userkey.DefaultAvatar[idx]
	up.Language = userkey.LanguageEnIN
	if resp.Data.Email != "" {
		up.Name = utils.FormatAccountByEmail(resp.Data.Email)
	} else {
		up.Name = utils.FormatAccountByName(resp.Data.Name)
	}

	// user notify msg stat
	unms := new(usercenter.UserNotifyMsgStat)
	unms.Uid = uac.Uid

	// user reward stat
	ugs := new(usercenter.UserRewardStat)
	ugs.Uid = uac.Uid
	ugs.NotReceived = 1 // 注册赠送金币
	ugs.Total = 1

	//
	unm := new(usercenter.UserReward)
	*unm = usercenter.UserReward{
		Uid:          uac.Uid,
		RewardType:   walletkey.UsingCurrencyType, //userkey.RewardTypeGold,
		RewardAmount: userkey.RegisterRewardMoneyAmount,
		ActivityId:   userkey.ActivityIdRegister,
		State:        userkey.RewardStateCreated,
	}

	//
	curTime := time.Now()
	url := new(usercenter.UserRewardLimit)
	*url = usercenter.UserRewardLimit{
		Uid:                   uac.Uid,
		TodayLuckyRewardCnt:   0,
		LuckyRewardUpdateTime: curTime,
		TodayLoginRewardCnt:   0,
		LoginRewardUpdateTime: curTime,
	}

	err = l._trans(uac, uls, up, unms, ugs, unm, url)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, err
	}

	// 生成token
	generateTokenLogic := NewGenerateTokenLogic(l.ctx, l.svcCtx)
	tokenResp, err := generateTokenLogic.GenerateToken(&pb.GenerateTokenReq{
		Uid:         uac.Uid,
		UserChannel: uac.UserChannel,
		AppVer:      in.AppVer,
		AuthKey:     resp.Data.Sub,
		AuthType:    userkey.UserAuthTypeGoogle,
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.TokenGenerateError, err.Error())
	}

	// app config
	var appConfig *usercenter.AppConfig
	appConfig, err = l.svcCtx.AppConfigModel.FindOne(l.ctx, in.AppVer)
	if err != nil && err != usercenter.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	rsp := pb.LoginUserResp{
		Account:       &pb.UserAccount{Uid: uac.Uid, AccountState: uac.AccountState, Username: up.Name, IsNewUser: dbkey.Disable},
		Profile:       &pb.UserProfile{Email: utils.FormatEmail(up.Email), AreaNo: up.AreaNo, PhoneNo: up.PhoneNo, Avatar: up.Avatar, Language: up.Language},
		Token:         tokenResp,
		NotifyMsgStat: &pb.UserNotifyMsgStat{},
		AppConfig:     &pb.AppConfig{},
		BannerConfig: &pb.BannerConfig{
			List: make([]*pb.BannerData, 0),
		},
		RewardStat: &pb.UserRewardStat{},
	}
	if appConfig != nil {
		rsp.AppConfig.PayState = appConfig.PayState
		rsp.AppConfig.TextState = appConfig.TextState
		rsp.AppConfig.RankState = appConfig.RankState
	}

	// banner config
	var bannerConfig []*usercenter.BannerConfig
	bannerConfig, err = l.svcCtx.BannerConfigModel.Find(l.ctx, userkey.BannerStateOpen, 1, 20)
	if len(bannerConfig) > 0 {
		for i := 0; i < len(bannerConfig); i++ {
			rsp.BannerConfig.List = append(rsp.BannerConfig.List, &pb.BannerData{
				Id:       bannerConfig[i].Id,
				Image:    bannerConfig[i].BannerImage,
				Url:      bannerConfig[i].Url,
				PagePath: bannerConfig[i].PagePath,
				Order:    bannerConfig[i].BannerOrder,
			})
		}
	}
	// 邀请注册，返回佣金, 走异步，不阻塞主流程
	l.afterHandleInvite(uid, in.DeviceId, uac.AuthKey, up.Name)
	// 给appsflyer上报事件， 走步调用， 不阻塞主流程
	l.RepoertAppsFlyerByFirstRegister(uac.AppsFlyerUid)
	// login log
	addLoginLog(l.ctx, l.svcCtx, uac.Uid, uac.UserChannel)

	// 保存历史记录
	_, err = l.svcCtx.UserVerifyLogModel.Insert(l.ctx, &usercenter.UserVerifyLog{Uid: uac.Uid, VerifyPass: in.GoogleToken})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
	}

	return &rsp, nil
}

func (l *RegisterLogic) afterHandleInvite(uid int64, deviceId string, authKey string, userName string) {
	l.Logger.Infof("[afterHandleInvite] user invitation start... uid: %d, deviceId: %s", uid, deviceId)
	// 根据deviceId,查询pid
	userInviteDevice, err := l.svcCtx.UserInviteDeviceModel.FindUserInviteDeviceByDeviceId(l.ctx, deviceId)
	if err != nil {
		l.Logger.Errorf("afterHandleInvite FindOneByDeviceId error. ", zap.Error(err))
		return
	}
	// 如果为空, 说明该用户没有被邀请 修改
	if userInviteDevice == nil {
		l.Logger.Infof("afterHandleInvite userInviteDevice is nil.")
		return
	}
	pid := userInviteDevice.Pid
	// 如果没有上级的pid，则直接return
	if pid == 0 {
		l.Logger.Infof("[afterHandleInvite] pid is zero... uid: %d, pid: %d", uid, pid)
		return
	}
	// 如果pid合法，则需要校验，pid是否存在，如果上级用户不存在，则直接return
	parentUser, err := l.svcCtx.UserAccountModel.FindOne(l.ctx, pid)
	if err != nil {
		l.Logger.Errorf("afterHandleInvite == ", zap.Error(err))
		return
	}
	if parentUser == nil {
		l.Logger.Errorf("afterHandleInvite parentUser is nil err: ", zap.Error(err))
		return
	}
	req := &usercenter.UserInvite{
		Uid:             uid,
		Pid:             pid,
		TotalAmount:     0,
		IsEffectiveUser: dbkey.Disable,
		AuthKey:         authKey,
		UserName:        userName,
	}

	err = l.svcCtx.UserInviteModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {

		_, err = l.svcCtx.UserInviteModel.Insert(l.ctx, req)
		if err != nil {
			l.Logger.Errorf("afterHandleInvite == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 注册就返回上级佣金
		// 查询佣金配置表
		userInviteConfigs, err := l.svcCtx.UserInviteConfigModel.Find(l.ctx)
		if len(userInviteConfigs) < 1 {
			l.Logger.Errorf("UserInviteConfig find error.  ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		// 默认读取一条配置，后续可能会优化
		userInviteConfig := userInviteConfigs[0]
		l.Logger.Infof("[afterHandleInvite]. userInviteConfig: %+v", userInviteConfig)
		// 计算充值余额
		moneyAmount := decimal.NewFromInt(userInviteConfig.ReturnNewRegisterMoney).StringFixedBank(2)
		l.Logger.Infof("[afterHandleInvite]. moneyAmount: %+v", moneyAmount)
		// 遍历每个上级，每个上级，都返还佣金
		_, err = l.svcCtx.WalletSysRpc.DepositDirect(l.ctx, &pb2.DepositDirectReq{
			Uid:            pid, // 级上级
			MoneyType:      walletkey.UsingCurrencyType,
			MoneyAmount:    moneyAmount,
			CurrencyType:   0,
			CurrencyAmount: "",
			PayChannelId:   walletkey.PayChannelIdSystem,
			ExFlow:         "",
		})
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			l.Logger.Errorf("UserRegisterLogic firstRegister DepositDirect uid:%d err:%v", uid, err)
			return err
		}
		// 新增邀请订单流水
		userInviteOrderFlow := &usercenter.UserInviteOrderFlow{
			Uid:         uid,
			Pid:         pid, // 上级
			MoneyType:   walletkey.UsingCurrencyType,
			MoneyAmount: userInviteConfig.ReturnNewRegisterMoney, // B端币种金额
			Type:        userkey.InviteRegisterType,              // 类型1：注册，2：充值
			RebateType:  userkey.InviteDirectlyRebateType,
		}
		_, err = l.svcCtx.UserInviteOrderFlowModel.Insert(l.ctx, userInviteOrderFlow)
		if err != nil {
			l.Logger.Errorf("[afterHandleInvite] UserInviteOrderFlowModel.Insert. err == ", zap.Error(err))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
		}
		l.Logger.Infof("user invitation end...")
		return nil
	})
}

func (l *RegisterLogic) RepoertAppsFlyerByFirstRegister(appsFlyerUid string) {
	// 首次注册
	appsflyer.ReportAppsFlyerEvent(l.ctx, appsflyerkey.Register, appsFlyerUid, "")
}
